import {
    BroadcastRequest,
    BroadcastResponse,
    BroadcastResponseStatus,
    Controller,
    ControllerNo,
    TimeControllerOpt
} from "./model/ControllerOpt";
import {ControllerBroadcast} from "./ControllerBroadcast";
import {SerializeBody} from "./model/SerializeBody";
import {FinalKey} from "../constant/FinalConstant";
import Configer from "../frame/apiModel/config/Configer";
import {SpecialEffectType} from "../type/Type";
import TimerUtil, {Timer, TimerStatus, TimerType} from "../frame/TimerUtil";
import {EffectModel} from "../frame/apiModel/adapterModel/model2/EffectModel";
import {ModelFactory} from "../frame/apiModel/adapterModel/model5/ModelFactory";
import {UnitModel} from "../frame/apiModel/adapterModel/model3/UnitModel";
import {LocModel} from "../frame/apiModel/base/LocModel";
import {PlayerModel} from "../frame/apiModel/adapterModel/model4/PlayerModel";
import {TimerModel} from "../frame/apiModel/adapterModel/model2/TimerModel";
import {GlobalModel} from "../frame/apiModel/adapterModel/model1/GlobalModel";
import {CodeUtil} from "../frame/codeAdapter/CodeUtil";
import {DataRouter} from "../frame/dataSource/DataRouter";
import {ResourceType} from "../frame/dataSource/DataModel";
import {Logger} from "../frame/apiModel/config/Logger";
import {ModelType} from "../frame/apiModel/adapter/adapterInterface/model5/IModelFactory";
import {ConfigKey} from "../constant/ConfigConstant";

// ---------------------------------------------------------------------------------------------------------------------------------------------------------------
export class TimerControl {
    ret: Timer;
    timer: TimerModel;

    constructor(ret: Timer, timer: TimerModel) {
        this.ret = ret;
        this.timer = timer;
    }

    end = () => {
        this.ret.end();
        this.timer && this.timer.destroy();
    }

    pause = () => {
        this.ret.pause();
        this.timer.pause();
    }
    resume = () => {
        this.ret.resume();
        this.timer.resume();
    }
}

export class TimeController implements Controller {
    getControllerNo(): number {
        return ControllerNo.TimerController;
    }
    private static timerController: TimeController = new TimeController();
    // 脱战计时器
    static getInstance() {
        return TimeController.timerController;
    }
    init = () => {
        TimerUtil.init();
        ControllerBroadcast.getInstance().startListen(TimeController.getInstance());
    }
    loadByJson(json: SerializeBody, player: PlayerModel) {
    }
    /**
     * @param timeOut
     * @param periodic
     * @param opt
     * opt中id为空不显示倒计时窗口
     * periodic设置-99代表无限循环
     * 还有优化空间： 每秒在左下角显示倒计时？
     * 无限计时器无法使用TimeRet对象暂停或停止
     */
    startTimer = (param: { time: number, opt: TimeControllerOpt }, timerType: TimerType = TimerType.main): TimerControl => {
        const id = param.opt.id;
        let periodic = false;
        if (param.opt.periodic > 1) {
            periodic = true
        }
        if (param.time === 0) {
            param.time = 0.1;
        }
        let periodicNum = param.opt.periodic;
        const foreverPeriodic = Configer.getFinal(FinalKey.foreverPeriodic) as number;
        const bLimit = (periodicNum === foreverPeriodic);
        let timer: TimerModel;
        if (!CodeUtil.isNullOrZero(id)) {
            timer = new TimerModel(id);
            const clearFun = function (this: void) {
                timer && timer.destroy();
            }
            timer.start(param.time, periodic, clearFun);
            const showDialog = Configer.getConfig(ConfigKey.showTimeDialog);
            if (showDialog > 0) {
                timer.showDialog(id)
            }
        }
        const callBack = function (this: void) {
            param.opt.callBack && param.opt.callBack(param.opt);
        }
        let ret: Timer;
        if (bLimit) {
            const status = TimerStatus.always
            ret = TimerUtil.runLater(param.time, callBack, 1, timerType, status)
        } else {
            const status = TimerStatus.nomal
            ret = TimerUtil.runLater(param.time, callBack, periodicNum, timerType, status)
        }
        const timerControl = new TimerControl(ret, timer)
        return timerControl;
    }
    notify(request: BroadcastRequest): BroadcastResponse {
        const ret: BroadcastResponse = { controllerNo: this.getControllerNo(), data: {}, status: BroadcastResponseStatus.success };
        const type = request.broadcastType;
        const data = request.data;
        switch (type) {
            default :
                ret.status = BroadcastResponseStatus.failed;
                break;
        }
        return ret;
    }
    serialize(player: PlayerModel): SerializeBody {
        return {};
    }

    static addSpecialEffectFun (activeUnit: UnitModel, path: string, time: number, loc: LocModel | undefined, point: string, type: SpecialEffectType, scale: number = 0, angle: number = 0){
        let effect: EffectModel;
        if (activeUnit?.isValid()) {
        } else {
            return ;
        }
        switch (type) {
            case SpecialEffectType.unit:{
                effect = ModelFactory.getInstance().createEffectInWidget(path, activeUnit, point);
                break;
            }
            case SpecialEffectType.point:{
                if (loc) {
                    effect = ModelFactory.getInstance().createEffectInPoint(path, loc);
                    const angle = activeUnit.loc.getAngle(loc);
                    effect.angleZ = angle;
                }
                break;
            }
        }
        if (effect) {
            if (!CodeUtil.isNullOrZero(scale)) {
                effect.setSize(scale, true);
            }
            if (!CodeUtil.isNullOrZero(angle)) {
                effect.angleZ = angle
            }

            const foreverPeriodic = Configer.getFinal(FinalKey.foreverPeriodic) as number;

            if (time === foreverPeriodic) {
            } else {
                const delCallBack = function () {
                    TimeController.RemoveEffect(effect)
                }
    
                let newTime = time ? time : 1;
    
                const timerOpt = new TimeControllerOpt(undefined, delCallBack, 1);
                TimeController.getInstance().startTimer({time: newTime, opt: timerOpt});
            }
        }
        return effect;
    }

    static addSpecialEffectByResourceIdFun (activeUnit: UnitModel, resourceId: string, time: number, loc: LocModel | undefined, point: string, type: SpecialEffectType, scale: number = 0, angle: number = 0) {
        const resourceData = DataRouter.getResourceDataByResourceId(resourceId);
        const resourceType = resourceData?.type;

        let newTime = time ? time : 1;

        if (resourceType === ResourceType.model) {
            const path = resourceData?.src;
            const effect = TimeController.addSpecialEffectFun(activeUnit, path, newTime, loc, point, type, scale, angle);
            return effect;
        } else {
            Logger.toastError(`对应的资源表Id ${resourceId} 所对应的资源类型 ${resourceType} 不正确！`);
        }
    }
    static RemoveEffect(effect: EffectModel) {
        ModelFactory.getInstance().destroy(effect, ModelType.effect);
    }

    startBackMusic(resourceId: string, interval: number = 10) {
        const resourceData = DataRouter.getResourceDataByResourceId(resourceId);
        if (resourceData) {
            const resourceType = resourceData?.type;
            if (resourceType === ResourceType.music) {
                const path = resourceData.src;
                GlobalModel.stopBackMusic(true);
    
                const gameTime = TimerUtil.getGameTime();
    
                GlobalModel.backMusicPath = path;
                GlobalModel.backMusicInterval = interval;
                GlobalModel.lastSetMusicTime = gameTime;
    
                const fun = function () {
                    const lastSetMusicTime = GlobalModel.lastSetMusicTime;
                    const backMusicPath = GlobalModel.backMusicPath;
                    const backMusicInterval = GlobalModel.backMusicInterval;
                    if (lastSetMusicTime === gameTime) {
                        GlobalModel.startBackMusic(backMusicPath);
                        const timerOpt = new TimeControllerOpt(undefined, fun, 1);
                        TimeController.getInstance().startTimer({ time: backMusicInterval, opt: timerOpt });
                    }
                }
                fun();
            } else {
                Logger.toastError(`对应的资源表Id ${resourceId} 所对应的资源类型 ${resourceType} 不正确！`);
            }
        } else {
            Logger.toastError(`未知的音乐文件！`);
        }

    }
}